package com.sikaryofficial.backend.manager.export;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.sikaryofficial.backend.config.ActivityConfig;
import com.sikaryofficial.backend.constant.DownloadTaskTypeEnum;
import com.sikaryofficial.backend.domain.entity.Activity;
import com.sikaryofficial.backend.domain.entity.ActivityAttendRec;
import com.sikaryofficial.backend.domain.entity.ActivityDelivery;
import com.sikaryofficial.backend.domain.entity.DownloadTask;
import com.sikaryofficial.backend.domain.entity.PointsBalance;
import com.sikaryofficial.backend.domain.mapping.DownloadTaskMapping;
import com.sikaryofficial.backend.domain.mapping.UserReportMapping;
import com.sikaryofficial.backend.domain.vo.export.ActivityAttendExportVO;
import com.sikaryofficial.backend.domain.vo.export.ActivityAttendStatisticsVO;
import com.sikaryofficial.backend.domain.vo.export.WinnerExportVO;
import com.sikaryofficial.backend.service.IActivityAttendRecService;
import com.sikaryofficial.backend.service.IActivityDeliveryService;
import com.sikaryofficial.backend.service.IActivityService;
import com.sikaryofficial.backend.service.IDownloadTaskService;
import com.sikaryofficial.backend.service.IPointsBalanceService;
import com.sikaryofficial.backend.service.IUserAddressService;
import com.sikaryofficial.backend.service.user.UserCacheService;
import com.sikaryofficial.backend.utils.ProductUtil;
import com.sikaryofficial.system.api.domain.SysUser;
import com.sikaryofficial.system.api.model.download.DownloadUrlDTO;
import com.univocity.parsers.common.processor.BeanWriterProcessor;
import com.univocity.parsers.csv.CsvWriter;
import com.univocity.parsers.csv.CsvWriterSettings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc : 活动导出
 * @date : 2023/10/30 15:39
 */
@Service
@Slf4j
@SuppressWarnings(value = "unchecked")
public class WinnerExportManager extends AbstractExportManager {
    @Autowired
    private IActivityService activityService;
    @Autowired
    private IDownloadTaskService downloadTaskService;
    @Autowired
    private ActivityConfig activityConfig;
    @Autowired
    private UserCacheService userCacheService;
    @Autowired
    private IActivityAttendRecService activityAttendRecService;
    @Autowired
    private IUserAddressService userAddressService;
    @Autowired
    private IActivityDeliveryService activityDeliveryService;
    @Autowired
    private IPointsBalanceService pointsBalance;

    /**
     * 获取文件下载地址 （获奖名单）
     *
     * @param activityId 活动ID
     * @return 文件下载地址对象
     */
    public List<DownloadUrlDTO> queryWinnerFilePath(Long activityId) {
        // 根据主键查询数据
        List<DownloadTask> downloadTask = downloadTaskService.getLatestTaskListById(activityId, DownloadTaskTypeEnum.ACTIVITY_WINNER.getCode());
        if (downloadTask.isEmpty()) {
            return Collections.emptyList();
        }
        return DownloadTaskMapping.INSTANCE.coverToUrlDTOList(downloadTask);
    }

    @Override
    public Integer getTaskTypeCode() {
        return DownloadTaskTypeEnum.ACTIVITY_WINNER.getCode();
    }

    @Override
    public String getTaskFolderPath(Long taskId) {
        return MessageFormat.format(activityConfig.getWinnerFolderPath(), taskId.toString());
    }

    @Override
    public void genFile(Long activityId, File folder) {
        long startTime = System.currentTimeMillis();
        log.info("生成文件开始, activityId: {}", activityId);
        genWinnerFile(activityId, folder);
        genAttendStatisticsFile(activityId, folder);
        genActivityAttendFile(activityId, folder);
        log.info("生成文件结束, activityId: {},  耗时: {} ms", activityId, System.currentTimeMillis() - startTime);
    }

    @Override
    public String genLocalZipFile(File folder, Long activityId, Long taskId) {
        return ProductUtil.genLocalZipFile(folder, activityId, taskId);
    }

    private void genWinnerFile(Long activityId, File folder) {
        try {
            List<WinnerExportVO> winnerExportVOList = activityService.winnerExport(activityId);
            if (winnerExportVOList.isEmpty()) {
                log.error("获奖者数据为空，不生成文件, activityId: {}", activityId);
                return;
            }
            buildAddressDetailObjExt(winnerExportVOList);
            String fileName = "中奖名单." + activityConfig.getWinnerFileType();
            String filePath = folder.getPath() + File.separator + fileName;
            EasyExcelFactory.write(Files.newOutputStream(new File(filePath).toPath()), WinnerExportVO.class).sheet("winnerList").doWrite(winnerExportVOList);
        } catch (IOException e) {
            log.error("生成获奖者数据Excel文件失败, activityId: {}, 错误信息: {}", activityId, e.getMessage(), e);
        }
    }

    private void buildAddressDetailObjExt(List<WinnerExportVO> winnerExportVOList) {
        List<Long> activityResultIds = winnerExportVOList.stream().map(WinnerExportVO::getActivityResultId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<ActivityDelivery> activityDeliveryResult = activityDeliveryService.lambdaQuery().eq(ActivityDelivery::getDeletedVersion, 0L).in(ActivityDelivery::getObjectId, activityResultIds).list();
        Map<Long, ActivityDelivery> activityResultMap = activityDeliveryResult.stream().collect(Collectors.toMap(ActivityDelivery::getObjectId, address -> address, (k1, k2) -> k1));
        for (WinnerExportVO item : winnerExportVOList) {
            setAddressDetailExt(item, activityResultMap);
        }
    }

    private void setAddressDetailExt(WinnerExportVO item, Map<Long, ActivityDelivery> resultMap) {
        ActivityDelivery addressUser = resultMap.getOrDefault(item.getActivityResultId(), null);
        if (Objects.isNull(addressUser)) {
            item.setAddressDetailObj("未关联收货地址");
            return;
        }
        try {
            item.setDeliveryEmail(addressUser.getAddressObj().getEmail());
            item.setPaymentAccount(addressUser.getAddressObj().getPaymentAccount());
            item.setAddressDetailObj(JSONObject.toJSONString(addressUser.getAddressObj()));
        } catch (Exception e) {
            log.error("地址序列化失败, createdBy: {}, 错误信息: {}", item.getCreatedBy(), e.getMessage(), e);
            item.setAddressDetailObj("地址序列化失败，请联系管理员");
        }
    }

    /**
     * 活动参与统计
     *
     * @param activityId
     * @param folder
     */
    private void genAttendStatisticsFile(Long activityId, File folder) {
        try {
            // 查询参与明细
            List<ActivityAttendStatisticsVO> activityAttendRecs = activityAttendRecService.queryStatistics(Lists.newArrayList(activityId));
            if (CollUtil.isEmpty(activityAttendRecs)) {
                log.error("活动参与统计导出为空，不生成文件, activityId: {}", activityId);
                return;
            }
            String fileName = "活动参与统计." + activityConfig.getCsvFileType();
            String filePath = folder.getPath() + File.separator + fileName;
            writerStatistics(activityAttendRecs, filePath);
        } catch (IOException e) {
            log.error("生成活动参与统计导出数据Excel文件失败, activityIds: {}, 错误信息: {}", activityId, e.getMessage(), e);
        }
    }

    private void writerStatistics(List<ActivityAttendStatisticsVO> userDailyDTOS, String filePath) throws IOException {
        // csvWriter
        CsvWriterSettings settings = new CsvWriterSettings();
        settings.setRowWriterProcessor(new BeanWriterProcessor<>(ActivityAttendStatisticsVO.class));
        CsvWriter csvWriter = new CsvWriter(Files.newOutputStream(new File(filePath).toPath()), settings);
        // header
        csvWriter.writeHeaders();
        // data
        csvWriter.processRecords(userDailyDTOS);
        // 刷新缓存
        csvWriter.flush();
    }

    /**
     * 活动参与明细
     *
     * @param activityId
     * @param folder
     */
    private void genActivityAttendFile(Long activityId, File folder) {
        try {
            // 查询活动详情
            Activity activity = activityService.lambdaQuery().select(Activity::getActivityName).eq(Activity::getDeletedVersion, 0L).eq(Activity::getActivityId, activityId).one();
            // 查询参与明细
            List<ActivityAttendRec> activityAttendRecs = activityAttendRecService.lambdaQuery().select(ActivityAttendRec::getCreatedBy, ActivityAttendRec::getCreatedTime).eq(ActivityAttendRec::getDeletedVersion, 0L).eq(ActivityAttendRec::getActivityId, activityId).orderByAsc(ActivityAttendRec::getCreatedBy).list();
            if (CollUtil.isEmpty(activityAttendRecs)) {
                log.error("活动参与明细导出为空，不生成文件, activityId: {}", activityId);
                return;
            }
            // 积分余额查询
            List<PointsBalance> pointsBalances = pointsBalance.lambdaQuery().eq(PointsBalance::getDeletedVersion, 0L).in(PointsBalance::getCreatedBy, activityAttendRecs.stream().map(ActivityAttendRec::getCreatedBy).collect(Collectors.toList())).list();
            // 获取 用户ID和积分余额的映射关系
            Map<Long, PointsBalance> pointsBalanceMap = pointsBalances.stream().collect(Collectors.toMap(PointsBalance::getCreatedBy, Function.identity(), (k1, k2) -> k1));
            // 分组统计
            Map<Long, Integer> userAttendNumMap = activityAttendRecs.stream().collect(Collectors.groupingBy(ActivityAttendRec::getCreatedBy, Collectors.summingInt(e -> 1)));

            List<ActivityAttendExportVO> resultList = UserReportMapping.INSTANCE.coverToActivityAttendList(activityAttendRecs);
            for (ActivityAttendExportVO item : resultList) {
                item.setActivityName(activity.getActivityName());
                SysUser sysUser = userCacheService.getSysUser(item.getCreatedBy());
                if (Objects.isNull(sysUser)) {
                    continue;
                }
                item.setEmail(sysUser.getEmail());
                item.setNickName(sysUser.getNickName());
                item.setRegisterTime(sysUser.getCreateTime());
                item.setCountry(sysUser.getCountry());
                item.setBalance(MapUtils.getObject(pointsBalanceMap, item.getCreatedBy(), new PointsBalance()).getBalance());
                item.setAttendNum(userAttendNumMap.getOrDefault(item.getCreatedBy(), 0));
            }
            String fileName = "活动参与明细." + activityConfig.getCsvFileType();
            String filePath = folder.getPath() + File.separator + fileName;
            writerFile(resultList, filePath);
        } catch (IOException e) {
            log.error("生成活动参与明细导出数据Excel文件失败, activityId: {}, 错误信息: {}", activityId, e.getMessage(), e);
        }
    }

    private void writerFile(List<ActivityAttendExportVO> userDailyDTOS, String filePath) throws IOException {
        // csvWriter
        CsvWriterSettings settings = new CsvWriterSettings();
        settings.setRowWriterProcessor(new BeanWriterProcessor<>(ActivityAttendExportVO.class));
        CsvWriter csvWriter = new CsvWriter(Files.newOutputStream(new File(filePath).toPath()), settings);
        // header
        csvWriter.writeHeaders();
        // data
        csvWriter.processRecords(userDailyDTOS);
        // 刷新缓存
        csvWriter.flush();
    }
}
